{UText3}
{TStyleSheet, TText, TTextImage, TTextView, TTextWriteUnivText}

{changed 05/11/84 1135  Changed TTextImage.InvalAll to call panel.InvalLRect}
{changed 04/26/84 1308  Changed TTextWriteUnivText.FillRun to TTextWriteUnivText.FillParagraph}
{changed 04/25/84 1250  Changed FilterAndDo calls back to filtering TParaImage for Compugraphic}
{changed 04/25/84 1135  Do same for TText.MarkChanged as for HiliteParagraphs below}
{changed 04/24/84 1637  Make TText.HiliteParagraphs use selection's textImage to call HiliteText}
{changed 04/20/84 1102  Modified TTextImage.ImageWith so that if it finds an image whose endLP equals
                            the passed lp then it may continue the scan, favoring the paraImage whose
                            textImage equals SELF}
{changed 04/17/84 1349  Erase/Invalidate bottom of textImage BEFORE calling nextTxtImg.RecomputeImages;
                        Fix boundary condition bug in TTextImage.RecomputeImages}
{changed 04/17/84 1110  Numerous additional explicit deletions of paraImages from paragraph.images}
{changed 04/16/84 1539  Set last parameter in NewView call in TTextView.CREATE to FALSE}
{changed 04/16/84 1446  Put picture comments in TTextImage.Draw}
{changed 04/16/84 1015  Explicitly delete paraImages from paragraph.images in TTextImage.RecomputeImages}
{changed 04/13/84 1818  Removed test to see if any paraImages in first textImage in TText.HiliteText and
                            TText.MarkChanged}
{changed 04/13/84 1537  Changed calls to FilterAndDo to pass TEditPara rather than TParaImage}
{changed 04/13/84 0209  Added TTextImage.NewEditPara}
{changed 04/10/84 1400  Changed references to TEditPara.images in DelPara, DelImagesWith, and ImageWith}
{changed 04/09/84 1337  Use deferUpdate in DrawOrInval and Recompute to decide if we should draw now}

{$S SgTxtHot}


METHODS OF TStyleSheet;

{$S SgTxtIni}
    FUNCTION TStyleSheet.CREATE(object: TObject; heap: THeap): TStyleSheet;
    VAR aList:  TList;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TStyleSheet(object);
        aList := TList.CREATE(NIL, heap, 0);
        SELF.formats := aList;
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtCld}
    PROCEDURE TStyleSheet.Free;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        Free(SELF.formats);
        SUPERSELF.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtIni}
    PROCEDURE TStyleSheet.InitDefault;
    VAR paraFormat: TParaFormat;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        paraFormat := TParaFormat.CREATE(NIL, SELF.Heap, SELF);
        SELF.formats.InsLast(paraFormat);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
{$IFC fTextTrace}
    PROCEDURE TStyleSheet.Fields(PROCEDURE Field(nameAndType: S255));
    BEGIN
        SUPERSELF.Fields(Field);
        Field('formats: TList');
        Field('');
    END;
{$ENDC}

{$S SgTxtIni}
END; {Methods of TStyleSheet}


METHODS OF TTextRange;

{$S SgTxtHot}
    FUNCTION TTextRange.CREATE(object: TObject; heap: THeap;
                                        beginPara: TEditPara; beginIndex: LONGINT; beginLP: INTEGER;
                                        endPara: TEditPara; endIndex: LONGINT; endLP: INTEGER): TTextRange;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TTextRange(object);
        WITH SELF DO
            BEGIN
            firstPara := beginPara;
            firstIndex := beginIndex;
            firstLP := beginLP;
            lastPara := endPara;
            lastIndex := endIndex;
            lastLP := endLP;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtCld}
{$IFC fTextTrace}
    PROCEDURE TTextRange.Fields(PROCEDURE Field(nameAndType: S255));
    BEGIN
        SUPERSELF.Fields(Field);
        Field('firstPara: TEditPara');
        Field('firstIndex: LONGINT');
        Field('firstLP: INTEGER');
        Field('lastPara: TEditPara');
        Field('lastIndex: LONGINT');
        Field('lastLP: INTEGER');
        Field('');
    END;
{$ENDC}


{$S SgTxtCld}
    PROCEDURE TTextRange.AdjustBy(delta: INTEGER);
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;



{$S SgTxtIni}
END;


METHODS OF TText;

{$S SgTxtIni}
    FUNCTION TText.CREATE(object: TObject; heap: THeap; itsStyleSheet: TStyleSheet): TText;
    VAR aList:	        TList;
        anotherList:    TList;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TText(object);
        aList := TList.CREATE(NIL, heap, 0);
        anotherList := TList.CREATE(NIL, heap, 0);
        WITH SELF DO
            BEGIN
            paragraphs := aList;
            txtImgList := anotherList;
            styleSheet := itsStyleSheet;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtCld}
    PROCEDURE TText.Free;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.FreeSelf(TRUE);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
{$IFC fTextTrace}
    PROCEDURE TText.Fields(PROCEDURE Field(nameAndType: S255));
    BEGIN
        SUPERSELF.Fields(Field);
        Field('paragraphs: TList');
        Field('styleSheet: TStyleSheet');
        Field('txtImgList: TList');
        Field('');
    END;
{$ENDC}


{$S SgTxtCld}
    PROCEDURE TText.FreeSelf(freeParas: BOOLEAN);
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.txtImgList.Free;
        IF freeParas THEN
            Free(SELF.paragraphs)	        {Free the paragraphs}
        ELSE IF SELF.paragraphs <> NIL THEN	      { OR }
            SELF.paragraphs.FreeObject;	        {Just Free the list}
        SUPERSELF.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtWrm}
    PROCEDURE TText.ChangeSelInOtherPanels(textSelection: TTextSelection);

        PROCEDURE ChngPanelSel(obj: TObject);
        VAR textImage:  TTextImage;
            selection:  TSelection;
            panel:      TPanel;
        BEGIN
            {$IFC fTrace}BP(10);{$ENDC}
            textImage := TTextImage(obj);
            panel := textImage.view.panel;
            selection := panel.selection;
            {We only unhighlight and replace the last non-NIL coSelection.  In most cases, where
             there is no coSelection, we unhighlight and replace the panel selection and
             everything is hunky-dory}
            WHILE selection.coSelection <> NIL DO
                selection := selection.coSelection;

            {Don't change selection in same panel}
            IF selection.panel <> textSelection.panel THEN
                selection := selection.FreedAndReplacedBy(textSelection.ReplicateForOtherPanel(textImage));
            {$IFC fTrace}EP;{$ENDC}
        END;

    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        IF SELF.txtImgList.size > 1 THEN
            SELF.txtImgList.Each(ChngPanelSel);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    PROCEDURE TText.DelPara(delPara: TEditPara;	 fFree: BOOLEAN);
    VAR (*
        i:	    INTEGER;
        numImages:  INTEGER;
        *)
        s:	    TListScanner;
        paraImage:  TParaImage;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        (*
        numImages := delPara.NumImages;
        FOR i := 1 TO numImages DO
        *)
        s := delPara.images.Scanner;
        WHILE s.Scan(paraImage) DO
            BEGIN
            (*
            paraImage := delPara.images[1];
            *)
            paraImage.textImage.imageList.DelObject(paraImage, FALSE);
            s.Delete(FALSE);
            paraImage.Free;
            END;
        {NOTE: We do not delete the paragraph from our own paragraphs list because this is usually
               called while scanning that list and we would screw up its scanner if we removed the
               paragraph from the list}
        IF fFree THEN
            delPara.free;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    PROCEDURE TText.Draw;
        PROCEDURE DrawInImage(obj: TObject);
        VAR textImage:  TTextImage;
            PROCEDURE DrawOnPad;
            BEGIN
                textImage.Draw;
            END;
        BEGIN
            textImage := TTextImage(obj);
            textImage.view.panel.OnAllPadsDo(DrawOnPad)
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.txtImgList.Each(DrawInImage);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    PROCEDURE TText.HiliteRange(highTransit: THighTransit; textRange: TTextRange; wholePara: BOOLEAN);
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        WITH textRange DO
            {$H-}
            SELF.HiliteParagraphs(highTransit, firstIndex, firstLP, lastIndex, lastLP, wholePara);
            {$H+}
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    { TText.HiliteParagraphs tells each text image to hilite its panel's text selection on each pad.  It
      calls TTextImage.HiliteText which assumes we are already focussed on a pad }
    PROCEDURE TText.HiliteParagraphs(highTransit: THighTransit;
                                                startIndex: LONGINT; startLP: INTEGER;
                                                endIndex: LONGINT; endLP: INTEGER; wholePara: BOOLEAN);
        PROCEDURE HiliteInImage(obj: TObject);
        VAR selection:  TSelection;
            textImage:  TTextImage;

            PROCEDURE HiliteOnPad;
            BEGIN
                textImage.HiliteText(highTransit, startIndex, startLP, endIndex, endLP, wholePara);
            END;
        BEGIN
            selection := TTextImage(obj).view.panel.selection;
            WHILE selection.coSelection <> NIL DO
                selection := selection.coSelection;
            textImage := TTextSelection(selection).textImage;
            textImage.view.panel.OnAllPadsDo(HiliteOnPad);
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.txtImgList.Each(HiliteInImage);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtIni}
    FUNCTION TText.DfltTextImage(view: TView; imageLRect: LRect; imgIsGrowable: BOOLEAN): TTextImage;
    VAR textImage:  TTextImage;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        textImage := TTextImage.CREATE(NIL, SELF.Heap, view, imageLRect, SELF, imgIsGrowable);
        SELF.txtImgList.InsLast(textImage);
        SELF.paragraphs.InsLast(textImage.NewEditPara(0, TParaFormat(SELF.styleSheet.formats.First)));
        SELF.RecomputeImages;
        DfltTextImage := textImage;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    PROCEDURE TText.InsParaAfter(existingPara: TEditPara;  newPara: TEditPara);

        PROCEDURE InsertPara(obj: TObject);
        BEGIN
            TTextImage(obj).InsertNewPara(existingPara, newPara);
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.txtImgList.Each(InsertPara);
        SELF.paragraphs.InsAt(SELF.paragraphs.Pos(0, existingPara) + 1, newPara);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    PROCEDURE TText.Invalidate;

        PROCEDURE InvalInImage(obj: TObject);
        VAR textImage:  TTextImage;
            PROCEDURE InvalOnPad;
            BEGIN
                textImage.Invalidate;
            END;
        BEGIN
            textImage := TTextImage(obj);
            IF textImage.imageList.Size > 0 THEN
                textImage.view.panel.OnAllPadsDo(InvalOnPad);
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.txtImgList.Each(InvalInImage);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    PROCEDURE TText.MarkChanged(textRange: TTextRange);

        PROCEDURE Mark(obj: TObject);
        VAR textImage:  TTextImage;
            selection:  TSelection;
        BEGIN
            selection := TTextImage(obj).view.panel.selection;
            WHILE selection.coSelection <> NIL DO
                selection := selection.coSelection;
            textImage := TTextSelection(selection).textImage;
            WITH textRange DO
                {$H-}
                textImage.MarkChanged(firstIndex, firstLP, lastIndex, lastLP);
                {$H+}
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.txtImgList.Each(Mark);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    PROCEDURE TText.RecomputeImages;
        PROCEDURE ReImage(obj: TObject);
        VAR textImage:  TTextImage;
            padCount:   INTEGER;
            numPads:    INTEGER;

            PROCEDURE ImageOnPad;
            BEGIN
                padCount := padCount+1;
                {The first parameter in textImage.RecomputeImages says we want to draw, but it will
                 call view.OKToDrawIn to be sure its Okay.
                 The last parameter is TRUE when we are drawing on the last pad.  RecomputeImages
                 and DrawOrInval will then set the valid bits on the images to TRUE}
                IF padCount = 1 THEN
                    textImage.RecomputeImages(actionDraw, (numPads = 1))
                ELSE
                    textImage.DrawOrInval(padCount = numPads);
            END;
        BEGIN
            textImage := TTextImage(obj);
            numPads := textImage.view.panel.panes.size;
            padCount := 0;
            textImage.view.panel.OnAllPadsDo(ImageOnPad);
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.txtImgList.Each(ReImage);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtWrm}
    FUNCTION TText.SelectAll(textImage: TTextImage): TTextSelection;
    VAR lastPara:   TEditPara;
        textSelection:	    TTextSelection;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        lastPara := TEditPara(SELF.paragraphs.Last);
        textSelection := textImage.NewTextSelection(TEditPara(SELF.paragraphs.First), 1, 0,
                                                        lastPara, SELF.paragraphs.Size, lastPara.size);
        SelectAll := textSelection;
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtIni}
BEGIN
    fTextTrace := FALSE;
END; {Methods of TText}


METHODS OF TTextImage;

{$S SgTxtIni}
    FUNCTION TTextImage.CREATE(object: TObject; heap: THeap; itsView: TView;
                                    itsLRect: LRect; itsText: TText; isGrowable: BOOLEAN): TTextImage;
    VAR imgList:    TList;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TTextImage(TImage.CREATE(object, heap, itsLRect, itsView));
        imgList := TList.CREATE(NIL, heap, 0);

        WITH SELF DO
            BEGIN
            text := itsText;
            imageList := imgList;
            tickCount := 0;
            growsDynamically := isGrowable;
            minHeight := itsLRect.bottom - itsLRect.top;
            formerBottom := itsLRect.top;
            updateLRect := zeroLRect;
            firstLinePixel := 0;
            useFirstPixel := FALSE;
            firstIndex := 1;
            startLP := 0;
            endLP := 0;
            {app must set these properly if using multiple linked text images}
            prevTxtImg := NIL;
            nextTxtImg := NIL;
            headTxtImg := SELF;
            tailTxtImg := SELF;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtCld}
    {This frees all text images and their paraImages in the text image chain.
     It does NOT free any paragraphs, text objects, or paraFormats.  Call this only once
     for each text image chain (NOT for each text image in the chain}
    PROCEDURE TTextImage.Free;
    VAR textImage:  TTextImage;
        next:	    TTextImage;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        IF SELF.headTxtImg = SELF THEN
            {Think about freeing text here if this is its only text image, but beware of circular frees}
                BEGIN
                textImage := SELF;
                WHILE textImage <> NIL DO
                    BEGIN
                    textImage.imageList.Free;
                    next := textImage.nextTxtImg;
                    textImage.FreeObject;
                    textImage := next;
                    END;
                END
        ELSE
            SELF.headTxtImg.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    {Frees just one text image in the chain; pays no attention to links}
    PROCEDURE TTextImage.FreeOneTextImage;
    VAR textImage:  TTextImage;
        next:	    TTextImage;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.imageList.Free;
        SELF.FreeObject;
        {$IFC fTrace}EP;{$ENDC}
    END;



{$S SgTxtCld}
{$IFC fTextTrace}
    PROCEDURE TTextImage.Fields(PROCEDURE Field(nameAndType: S255));
    BEGIN
        SUPERSELF.Fields(Field);
        Field('text: TText');
        Field('imageList: TList');
        Field('tickCount: INTEGER');
        Field('growsDynamically: BOOLEAN');
        Field('minHeight: INTEGER');
        Field('formerBottom: LONGINT');
        Field('updateLRect: LRect');
        Field('firstLinePixel: LONGINT');
        Field('useFirstPixel: BOOLEAN');
        Field('firstIndex: LONGINT');
        Field('startLP: INTEGER');
        Field('endLP: INTEGER');
        Field('prevTxtImg: TTextImage');
        Field('nextTxtImg: TTextImage');
        Field('headTxtImg: TTextImage');
        Field('tailTxtImg: TTextImage');
        Field('');
    END;
{$ENDC}


{$S SgTxtCld}
    PROCEDURE TTextImage.AddImage(paraImage: TParaImage);
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.imageList.InsLast(paraImage);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    PROCEDURE TTextImage.DelImagesWith(delPara: TEditPara);
    VAR (*
        i,j:	    INTEGER;
        numImages:  INTEGER;
        *)
        s:	    TListScanner;
        paraImage:  TParaImage;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        s := delPara.images.Scanner;
        WHILE s.Scan(paraImage) DO
            IF paraImage.textImage.headTxtImg = SELF.headTxtImg THEN
                BEGIN
                paraImage.textImage.imageList.DelObject(paraImage, FALSE);
                s.Delete(FALSE);
                paraImage.Free;
                END;
        (*
        numImages := delPara.NumImages;
        j := 1;
        FOR i := 1 TO numImages DO
            BEGIN
            {paraImage.Free calls paragraph.DelImage which shifts rest
             of images left so next image will always be at position j}
            paraImage := delPara.images[j];
            IF paraImage.textImage.headTxtImg = SELF.headTxtImg THEN
                paraImage.textImage.imageList.DelObject(paraImage, TRUE)
            ELSE
                j := j + 1;
            END;
        *)
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtWrm}
    PROCEDURE TTextImage.Draw;
        PROCEDURE ReDraw(obj: TObject);
        BEGIN
            IF LRectIsVisible(TParaImage(obj).extentLRect) THEN
                TParaImage(obj).RedrawLines(0, MAXINT);
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        PicGrpBegin;
        SELF.imageList.Each(ReDraw);
        {Now tell the next textImage in the chain to draw itself}
        IF SELF.nextTxtImg <> NIL THEN
            SELF.nextTxtImg.Draw;

        PicGrpEnd;
        {$IFC fTrace}EP;{$ENDC}
    END; {Draw}


{$S SgTxtCld}
    PROCEDURE TTextImage.DrawImages(fDraw: BOOLEAN);
        PROCEDURE ReDraw(obj: TObject);
        BEGIN
            IF LRectIsVisible(TParaImage(obj).extentLRect) THEN
                TParaImage(obj).RedrawLines(0, MAXINT);
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.imageList.Each(ReDraw);
        {Now tell the next textImage in the chain to draw itself}
        IF SELF.nextTxtImg <> NIL THEN
            SELF.nextTxtImg.DrawImages(fDraw);
        {$IFC fTrace}EP;{$ENDC}
    END; {DrawImages}


{$S SgTxtCld}
    PROCEDURE TTextImage.DrawOrInval(invalBits: BOOLEAN);
    VAR fDraw:	    BOOLEAN;
        r:	    LRect;

        PROCEDURE DrawFiltImage(obj: TObject);
        VAR paraImage:  TParaImage;

            PROCEDURE DrawImage(obj: TObject);
            VAR leftPixel:  LONGINT;
                rightPixel: LONGINT;
                styleIndex: INTEGER;

                PROCEDURE DrawLine(obj: TObject);
                VAR lineInfo:   TLineInfo;
                    dummy:      INTEGER;
                BEGIN
                    lineInfo := TLineInfo(obj);
                    IF NOT lineInfo.valid THEN
                        BEGIN
                        r := lineInfo.lineLRect;
                        r.left := lineInfo.leftCoord(leftPixel);
                        r.right := lineInfo.leftCoord(rightPixel);
                        IF fDraw THEN
                            BEGIN
                            FillLRect(r, lPatWhite);
                            IF lineInfo.startLP <> lineInfo.lastDrawnLP THEN
                                BEGIN
                                MoveToL(lineInfo.lineLRect.left, lineInfo.lineLRect.top+lineInfo.lineAscent);
                                paraImage.FastDrawLine(lineInfo.startLP, lineInfo.lastDrawnLP, TRUE,
                                                        FALSE, dummy, styleIndex);
                                END;
                            END
                        ELSE
                            thePad.InvalLRect(r);
                        lineInfo.valid := invalBits;
                        END;
                END;

            BEGIN
                IF paraImage.wasOffset THEN
                    BEGIN
                    {possibly use ScrollRect here later?}
                    r := paraImage.extentLRect;
                    InsetLRect(r, -1, 0);
                    IF fDraw THEN
                        BEGIN
                        FillLRect(r, lPatWhite);
                        paraImage.RedrawLines(0, MAXINT);
                        END
                    ELSE
                        thePad.InvalLRect(r);
                    paraImage.wasOffset := NOT invalBits;
                    END
                ELSE IF paraImage.changed THEN
                    BEGIN
                    leftPixel := paraImage.extentLRect.left-1;
                    rightPixel := paraImage.extentLRect.right+1;
                    styleIndex := 1;
                    paraImage.lineList.Each(DrawLine);
                    paraImage.changed := NOT invalBits;
                    END;
            END;

        BEGIN
            paraImage := TParaImage(obj);
            SELF.FilterAndDo(paraImage, DrawImage);
        END;

    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        fDraw := SELF.view.OKToDrawIn(SELF.extentLRect) AND NOT deferUpdate;
        SELF.imageList.Each(DrawFiltImage);

        IF NOT EmptyLRect(SELF.updateLRect) THEN
            BEGIN
            IF fDraw THEN
                FillLRect(SELF.updateLRect, lPatWhite)
            ELSE
                thePad.InvalLRect(SELF.updateLRect);
            IF invalBits THEN
                SELF.updateLRect := zeroLRect;
            END;
        {Now tell the next textImage in the chain to draw itself}
        IF SELF.nextTxtImg <> NIL THEN
            SELF.nextTxtImg.DrawOrInval(invalBits);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    PROCEDURE TTextImage.FindParaAndLp(lPt: LPoint; VAR paraImage: TParaImage;
                                                       VAR paraIndex: LONGINT; VAR aLP: INTEGER);
    VAR distanceDown:   INTEGER;
        s:	        TListScanner;
        {$IFC fTextTrace}
        str:	        STR255;
        {$ENDC}
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}

        {It is assumed that the caller of this routine has already determined that lPt is in this
         textImage, so we will not check nextTextImg if the image list is exhausted}
        distanceDown := SELF.extentLRect.top;
        s := SELF.imageList.Scanner;
        WHILE s.Scan(paraImage) DO
            BEGIN
            distanceDown := distanceDown + paraImage.height;
            paraIndex := s.Position;
            IF lPt.v <= distanceDown THEN
                s.Done;
            END;

        paraIndex := paraIndex + SELF.firstIndex - 1;

        IF lPt.v > distanceDown THEN
            paraImage := TParaImage(SELF.imageList.Last);

        aLP := paraImage.LpWithLPt(lPt);
        {$IFC fTextTrace}
        IF fTextTrace THEN
            BEGIN
            LIntToHex(ORD(paraImage), @str);
            writeln('*** End FindParaAndLp: lPt= (',lPt.v:4, ',', lPt.h:4, ');  paraImage, index, lp = (',
                                 str, ',', paraIndex:1, ',', aLP:3, ')');
            END;
        {$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;



{$S SgTxtHot}
    FUNCTION  TTextImage.FindTextImage(VAR mouseLPt: LPoint; VAR firstTxtImg: TTextImage): TTextImage;
    VAR textImage:      TTextImage;
        stillLooking:   BOOLEAN;
        foundIt:        BOOLEAN;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        {This looks around for a textImage that contains the mouseLPt and has some images.  If it
         finds a textImage that contains the point but does not have any images, then it
         returns the first previous textImage that does have some images and changes mouseLPt to be
         the bottom right point of that textImage.
         If it doesn't find any textImages that contain the point it returns the first previous
         textImage that does have some images.  Also, it returns which of the textImages
         (SELF or the found one) that comes first in the textImage chain}

        firstTxtImg := SELF;
        {Start with most common case and then try others}
        IF (SELF.imageList.Size > 0) AND
                (LPtInLRect(mouseLPt, SELF.extentLRect) OR SELF.growsDynamically) THEN
            FindTextImage := SELF
        ELSE
            BEGIN
            textImage := SELF;
            stillLooking := TRUE;
            foundIt := FALSE;
            WHILE stillLooking DO
                BEGIN
                {First look in following boxes}
                IF LPtInLRect(mouseLPt, textImage.extentLRect) THEN
                    BEGIN
                    {if box found but no images in it, then link back}
                    WHILE (textImage <> textImage.headTxtImg) AND (textImage.imageList.Size = 0) DO
                        BEGIN
                        textImage := textImage.prevTxtImg;
                        mouseLPt := textImage.extentLRect.botRight;
                        END;
                    foundIt := TRUE;
                    stillLooking := FALSE;
                    END
                ELSE IF textImage.nextTxtImg <> NIL THEN
                    textImage := textImage.nextTxtImg
                ELSE stillLooking := FALSE;
                END;

            IF foundIt THEN
                FindTextImage := textImage
            ELSE
                {Still didn't find it?  Look in previous boxes}
                BEGIN
                stillLooking := TRUE;
                WHILE stillLooking DO
                    BEGIN
                    IF LPtInLRect(mouseLPt, textImage.extentLRect) THEN
                        BEGIN
                        WHILE (textImage <> textImage.headTxtImg) AND (textImage.imageList.Size = 0) DO
                            BEGIN
                            textImage := textImage.prevTxtImg;
                            mouseLPt := textImage.extentLRect.botRight;
                            END;
                        foundIt := TRUE;
                        stillLooking := FALSE;
                        END
                    ELSE IF textImage.prevTxtImg <> NIL THEN
                        textImage := textImage.prevTxtImg
                    ELSE stillLooking := FALSE;
                    END;
                IF foundIt THEN
                    BEGIN
                    FindTextImage := textImage;
                    firstTxtImage := textImage;
                    END
                ELSE
                    BEGIN
                    {mouseLPt didn't fall in any of the text images, so return SELF or the first previous
                     text image that has a paraimage}
                    textImage := SELF;
                    WHILE (textImage <> textImage.headTxtImg) AND (textImage.imageList.Size = 0) DO
                       BEGIN
                       textImage := textImage.prevTxtImg;
                       mouseLPt := textImage.extentLRect.botRight;
                       END;
                    FindTextImage := textImage;
                    END;
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    PROCEDURE TTextImage.GetImageRange(firstIndex: LONGINT; VAR firstLP: INTEGER;
                                          lastIndex:  LONGINT; VAR lastLP:  INTEGER;
                                          VAR firstImage, lastImage: TParaImage);

    {Diagram of input vs output:  --- = characters not displayed by this textImage chain;
                                  xxx = characters that are displayed by this textImage chain;

        ------------xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx----------
          ^    ^    ^	    ^			   ^    ^  ^
          1    2    3	    4			   5    6  7


        input   imageWith     output
         1,2	    N,N	        N,N
         1,3	    N,3	        N,3
         1,4	    N,4	        3,4
         1,5	    N,5	        3,5
         1,6	    N,N	        3,5
         3,3	    3,3	        3,3	        N = NIL
         3,4	    3,4	        3,4
         4,5	    4,5	        4,5
         4,6	    4,N	        4,5
         5,5	    5,5	        5,5
         5,6	    5,N	        5,N
         6,7	    N,N	        N,N
      }

        FUNCTION GetFirstOrLast(index: LONGINT; VAR lp: INTEGER): TParaImage;
        VAR paraImage:  TParaImage;
            lastTxtImg: TTextImage;
        BEGIN
            {$IFC fTrace}BP(10);{$ENDC}
            IF (index < SELF.headTxtImg.firstIndex) OR
               ((index = SELF.headTxtImg.firstIndex) AND (lp < SELF.headTxtImg.startLP)) THEN
                BEGIN
                paraImage := TParaImage(SELF.headTxtImg.imageList.First);
                lp := paraImage.startLP;
                END
            ELSE
                BEGIN
                lastTxtImg := SELF.tailTxtImg;
                WHILE lastTxtImg.imageList.Size <= 0 DO
                    lastTxtImg := lastTxtImg.prevTxtImg;
                paraImage := TParaImage(lastTxtImg.imageList.Last);
                lp := paraImage.endLP;
                END;
            GetFirstOrLast := paraImage;
            {$IFC fTrace}EP;{$ENDC}
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        firstImage := SELF.ImageWith(TEditPara(SELF.text.paragraphs.At(firstIndex)), firstLP);
        lastImage := SELF.ImageWith(TEditPara(SELF.text.paragraphs.At(lastIndex)), lastLP);

        IF (firstImage = NIL) OR (lastImage = NIL) THEN
            BEGIN
            IF firstImage = NIL THEN
                IF lastImage <> NIL THEN
                    BEGIN
                    firstImage := GetFirstOrLast(firstIndex, firstLP);
                    IF (firstImage = lastImage) THEN
                        IF (firstLP = lastLP) THEN
                            firstImage := NIL;
                    END
                ELSE
                    BEGIN
                    firstImage := GetFirstOrLast(firstIndex, firstLP);
                    lastImage := GetFirstOrLast(lastIndex, lastLP);
                    IF (firstImage = lastImage) AND (firstLP = lastLP) THEN
                        BEGIN
                        firstImage := NIL;
                        lastImage := NIL;
                        END;
                    END
            ELSE
                BEGIN
                lastImage := GetFirstOrLast(lastIndex, lastLP);
                IF (firstImage = lastImage) THEN
                    IF (firstLP = lastLP) THEN
                        lastImage := NIL;
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    PROCEDURE TTextImage.HiliteText(highTransit: THighTransit;
                                                startIndex: LONGINT; startLP: INTEGER;
                                                endIndex: LONGINT; endLP: INTEGER; wholePara: BOOLEAN);
    LABEL 1;
    VAR startImage:     TParaImage;
        endImage:       TParaImage;
        r:	        LRect;
        lineInfo:       TLineInfo;
        paraImage:      TParaImage;
        sImg, sViewSt:  TListScanner;
        startLine:      INTEGER;
        endLine:        INTEGER;
        startPixel:     LONGINT;
        endPixel:       LONGINT;
        lMargPixel:     LONGINT;
        rMargPixel:     LONGINT;
        i:	        INTEGER;
        textImage:      TTextImage;
        stillOkay:      BOOLEAN;
        {$IFC fTextTrace}
        str1:	        STR255;	    {for debug output}
        str2:	        STR255;	    {for debug output}
        {$ENDC}
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        {$IFC fTextTrace}
        IF fTextTrace THEN
            BEGIN
            Writeln('*** In HiliteText:	 [(', startIndex:1, ',', startLP:1, ') , (',
                                        endIndex:1, ',', endLP:1,
                                        ')];  highTransit = ', ORD(highTransit):2);
            LIntToHex(ORD(SELF), @str1);
            WriteLn('*** SELF = ', str1, '  SELF.endLP=', SELF.endLP:1);
            END;
        {$ENDC}

        IF (startIndex = endIndex) AND (startLP = endLP) THEN
            BEGIN
            startImage := SELF.ImageWith(TEditPara(SELF.text.paragraphs.At(startIndex)), startLP);
            endImage := startImage;
            stillOkay := startImage <> NIL;
            END
        ELSE
            BEGIN
            SELF.GetImageRange(startIndex, startLP, endIndex, endLP, startImage, endImage);
            stillOkay := (startImage <> NIL) AND (endImage <> NIL);
            END;

        IF stillOkay THEN
            BEGIN
            textImage := startImage.textImage;

            lMargPixel := textImage.extentLRect.left - 1;
            rMargPixel := textImage.extentLRect.right + 1;

            IF highTransit = hDimToOn THEN
                BEGIN
                SELF.HiliteText(hDimToOff, startIndex, startLP, endIndex, endLP, wholePara);
                highTransit := hOffToOn;
                END
            ELSE IF highTransit = hOffToDim THEN
                BEGIN
                SELF.HiliteText(hOffToOn, startIndex, startLP, endIndex, endLP, wholePara);
                highTransit := hOnToDim;
                END;

            IF highTransit <> hNone THEN
                BEGIN
                SetPenState(highPen[highTransit]);
                IF highTransit = hOnToDim THEN
                    PenMode(notPatBic); { hOnToDim  => change background from black to gray }

                sImg := textImage.imageList.Scanner;
                WHILE sImg.Scan(paraImage) DO
                    IF paraImage = startImage THEN
                        GOTO 1;

                1:
                paraImage.LocateLP(startLP, startLine, startPixel);

                sViewSt := paraImage.lineList.Scanner;
                i := 0;
                REPEAT
                    IF sViewSt.Scan(lineInfo) THEN
                        i := i+1;
                UNTIL i = startLine;

                r := lineInfo.lineLRect;
                IF wholePara THEN
                    r.left := lineInfo.LeftCoord(lMargPixel)
                ELSE
                    r.left := startPixel;
                r.right := lineInfo.RightCoord(rMargPixel);
                WHILE paraImage <> endImage DO
                    BEGIN
                    WHILE sViewSt.Scan(lineInfo) DO
                        BEGIN
                        PaintLRect(r);
                        {$IFC fTextTrace}
                        IF fTextTrace THEN
                            BEGIN
                            WriteLn('*** Within HiliteText: about to paintLRect: [(', r.left:1, ',',
                                            r.top:1,'),(', r.left:1,',',r.right:1,')]' );
                            LIntToHex(ORD(paraImage), @str1);
                            WriteLn('*** current paraImage=',str1);
                            END;
                        {$ENDC}
                        r := lineInfo.lineLRect;
                        r.left := lineInfo.LeftCoord(lMargPixel);
                        r.right := lineInfo.RightCoord(rMargPixel);
                        END;
                    IF sImg.Scan(paraImage) THEN
                        sViewSt := paraImage.lineList.Scanner
                    ELSE
                        BEGIN
                        textImage := textImage.nextTxtImage;
                        lMargPixel := textImage.extentLRect.left-1;
                        rMargPixel := textImage.extentLRect.right+1;
                        sImg := textImage.imageList.Scanner;
                        IF sImg.Scan(paraImage) THEN
                            sViewSt := paraImage.lineList.Scanner;
                        END;
                    END;
                paraImage.LocateLP(endLP, endLine, endPixel);

                IF startImage <> endImage THEN
                    BEGIN
                    PaintLRect(r);
                    sViewSt := paraImage.lineList.Scanner;
                    IF sViewSt.Scan(lineInfo) THEN
                        BEGIN
                        r := lineInfo.lineLRect;
                        r.left := lineInfo.LeftCoord(lMargPixel);
                        r.right := lineInfo.RightCoord(rMargPixel);
                        END;
                    i := 1;
                    END;

                WHILE i <> endLine DO
                    BEGIN
                    PaintLRect(r);
                    IF sViewSt.Scan(lineInfo) THEN
                        BEGIN
                        r := lineInfo.lineLRect;
                        r.left := lineInfo.LeftCoord(lMargPixel);
                        r.right := lineInfo.RightCoord(rMargPixel);
                        END;
                    i := i+1;
                    END;

                IF wholePara THEN
                    r.right := lineInfo.RightCoord(rMargPixel)
                ELSE
                    BEGIN
                    r.right := endPixel;
                    {Add extra pixel if this is insertion point}
                    IF (startImage = endImage) AND (startLP = endLP) THEN
                        r.right := r.right + 1;
                    END;
                PaintLRect(r);

                Free(sViewSt);
                Free(sImg);

                IF highTransit = hDimToOff THEN { XORing out gray leaves holes in chars }
                    BEGIN
                    {later, we'll minimize this, if necessary}
                    SELF.Draw;	   { so redraw characters }
                    END;
                END;
            END
        ELSE
            BEGIN
            {$IFC fTextTrace}
            IF fTextTrace THEN
                BEGIN
                Writeln('*** In HiliteText:  Images NIL (DID NOT HILITE))');
                END;
            {$ENDC}
            END;
        {$IFC fTrace}EP;{$ENDC}
    END; {HiliteText}


{$S SgTxtHot}
    {Given a paragraph and lp finds the paraImage that displays it in this textImage chain.
     Returns NIL if not found.}
    FUNCTION  TTextImage.ImageWith(paragraph: TEditPara; lp: INTEGER): TParaImage;
    VAR paraImage:      TParaImage;
        altParaImage:   TParaImage;
        s:	        TListScanner;
        (*
        i:	    INTEGER;
        *)
        {$IFC fTextTrace}
        str:	     STR255;
        {$ENDC}
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        {$IFC fTextTrace}
        IF fTextTrace THEN
            BEGIN
            LIntToHex(ORD(paragraph), @str);
            WriteLn('$$$ In ImageWith: paragraph,lp = (',str, ',', lp:1, ')' );
            END;
        {$ENDC}

        altParaImage := NIL;
        s := paragraph.images.Scanner;
        WHILE s.Scan(paraImage) DO
            IF ((paraImage.textImage.headTxtImg = SELF.headTxtImg) AND
                (paraImage.startLP <= lp) AND
                (lp <= paraImage.endLP)) THEN
                    IF lp = paraImage.endLP THEN
                        IF paraImage.textImage <> SELF THEN
                            altParaImage := paraImage
                        ELSE
                            s.Done
                    ELSE
                        s.Done;

        IF paraImage = NIL THEN
            paraImage := altParaImage;
        (*
        i := 1;
        WITH paragraph DO
            {$R-}
            WHILE (i <= numImages) DO
                IF ((images[i].textImage.headTxtImg = SELF.headTxtImg) AND
                    (images[i].startLP <= lp) AND
                    (lp <= images[i].endLP)) THEN
                        BEGIN
                        paraImage := images[i];
                        i := MAXINT;
                        END
                ELSE
                    i := i + 1;
            {$IFC fRngText}{$R+}{$ENDC}
        *)

        {$IFC fTextTrace}
        IF fTextTrace THEN
            BEGIN
            LIntToHex(ORD(paraImage), @str);
            WriteLn('$$$ In ImageWith: paraImage found= ',str);
            END;
        {$ENDC}

        ImageWith := paraImage;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    FUNCTION TTextImage.ImageBottom: LONGINT;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        IF SELF.imageList.Size > 0 THEN
            ImageBottom := TParaImage(SELF.imageList.Last).extentLRect.bottom
        ELSE
            ImageBottom := SELF.extentLRect.top;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    PROCEDURE TTextImage.InsertNewPara(existingPara, newPara: TEditPara);
    VAR paraImage:      TParaImage;
        lastImage:      TParaImage;
        newParaImage:   TParaImage;
        textImage:      TTextImage;
        {$IFC fTextTrace}
        str:	        STR255;
        {$ENDC}
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        {Try to find the image with the proper lp, but, failing that, see if there is any image that
         points to existingPara}
        paraImage := SELF.ImageWith(existingPara, existingPara.size - 1);
        IF paraImage = NIL THEN
            paraImage := SELF.ImageWith(existingPara, 0);
        IF paraImage = NIL THEN
            BEGIN
            {$IFC fTextTrace}
            IF fTextTrace THEN
                BEGIN
                LIntToHex(ORD(existingPara), @str);
                WriteLn('@@@ In InsertNewPara: existingPara = (',str,')' );
                WriteLn('@@@   ImageWith returned NIL!!');
                END;
            {$ENDC}
            END
        ELSE
            BEGIN
            textImage := paraImage.textImage;
            lastImage := TParaImage(textImage.imageList.Last);
            newParaImage := textImage.NewParaImage(newPara, paraImage.extentLRect, 0, 0);
            textImage.imageList.InsAt(textImage.imageList.Pos(0, paraImage) + 1, newParaImage);

            {If we inserted the new paraImage at the end of the current image list and if the
             last paragraph was previously split between two or more paraImages, then set the paragraph
             field in the first image of the next text image to the new paragraph, and adjust the
             paragraphs' images accordingly}
            IF (paraImage = lastImage) THEN
                BEGIN
                textImage := paraImage.textImage.nextTxtImg;
                WHILE (textImage <> NIL) DO
                    IF textImage.imageList.Size > 0 THEN
                        BEGIN
                        paraImage := TParaImage(textImage.imageList.First);
                        IF paraImage.paragraph = lastImage.paragraph THEN
                            BEGIN
                            paraImage.paragraph := newPara;
                            newPara.InsImage(paraImage);     {|}
                            lastImage.paragraph.DelImage(paraImage, FALSE); {|}
                            textImage := textImage.nextTxtImg;
                            END
                        ELSE
                            textImage := NIL
                        END
                    ELSE
                        textImage := NIL
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    PROCEDURE TTextImage.InvalAll;
    VAR r:	    LRect;
        textImage:  TTextImage;

        PROCEDURE Inval(obj: TObject);
        BEGIN
            TParaImage(obj).InvalLinesWith(0, MAXINT);
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        textImage := SELF.headTxtImg;
        WHILE textImage <> NIL DO
            BEGIN
            textImage.imageList.Each(Inval);
            r := textImage.extentLRect;
            InsetLRect(r, -1, 0);
            SELF.view.panel.InvalLRect(r);
            textImage := textImage.nextTxtImg;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    PROCEDURE TTextImage.Invalidate;
    VAR r:	    LRect;
        s, sLine:   TListScanner;
        paraImage:  TParaImage;
        lineInfo:   TLineInfo;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        s := SELF.imageList.Scanner;
        WHILE s.Scan(paraImage) DO
            IF paraImage.wasOffset THEN
                BEGIN
                r := paraImage.extentLRect;
                InsetLRect(r, -1, 0);
                thePad.InvalLRect(r);
                paraImage.wasOffset := FALSE;
                paraImage.changed := FALSE;
                END
            ELSE IF paraImage.changed THEN
                BEGIN
                paraImage.changed := FALSE;
                sLine := paraImage.lineList.Scanner;
                WHILE sLine.Scan(lineInfo) DO
                    IF NOT lineInfo.valid THEN
                        BEGIN
                        lineInfo.valid := TRUE;
                        r := lineInfo.lineLRect;
                        r.left := paraImage.extentLRect.left;
                        r.right := paraImage.extentLRect.right;
                        InsetLRect(r, -1, 0);
                        thePad.InvalLRect(r);
                        END;
                END;

        IF NOT EmptyLRect(SELF.updateLRect) THEN
            BEGIN
            thePad.InvalLRect(SELF.updateLRect);
            SELF.updateLRect := zeroLRect;
            END;

        IF SELF.nextTxtImg <> NIL THEN
            SELF.nextTxtImg.Invalidate;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    PROCEDURE TTextImage.MarkChanged(startIndex: LONGINT; startLP: INTEGER;
                                            endIndex: LONGINT; endLP: INTEGER);
    VAR sImg:	    TListScanner;
        firstImage: TParaImage;
        lastImage:  TParaImage;
        paraImage:  TParaImage;
        found:	    BOOLEAN;
        finished:   BOOLEAN;
        textImage:  TTextImage;
        tempLP:	    INTEGER;
        stillOkay:  BOOLEAN;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        stillOkay := TRUE;
        IF (startIndex = endIndex) AND (startLP = endLP) THEN
            BEGIN
            firstImage := SELF.ImageWith(TEditPara(SELF.text.paragraphs.At(startIndex)), startLP);
            lastImage := firstImage;
            stillOkay := firstImage <> NIL;
            END
        ELSE
            BEGIN
            SELF.GetImageRange(startIndex, startLP, endIndex, endLP, firstImage, lastImage);
            IF firstImage = NIL THEN
                IF lastImage = NIL THEN
                    stillOkay := FALSE
                ELSE
                    BEGIN
                    firstImage := lastImage;
                    startLP := endLP;
                    END
            ELSE IF lastImage = NIL THEN
                    BEGIN
                    lastImage := firstImage;
                    endLP := startLP;
                    END;
            END;

        IF stillOkay THEN
            BEGIN
            IF firstImage = lastImage THEN
                firstImage.InvalLinesWith(startLP, endLP)
            ELSE
                BEGIN
                textImage := firstImage.textImage;
                found := FALSE;
                finished := FALSE;
                WHILE NOT finished AND (textImage <> NIL) DO
                    BEGIN
                    sImg := textImage.imageList.Scanner;
                    WHILE sImg.Scan(paraImage) DO
                        BEGIN
                        found := found OR (paraImage = firstImage);
                        IF found THEN
                            BEGIN
                            IF paraImage = lastImage THEN
                                BEGIN
                                tempLP := endLP;
                                finished := TRUE;
                                sImg.Done;
                                END
                            ELSE
                                tempLP := paraImage.endLP;
                            paraImage.InvalLinesWith(startLP, tempLP);
                            startLP := 0;
                            END;
                        END;
                    textImage := textImage.nextTxtImg;
                    END;
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    PROCEDURE TTextImage.MousePress(mouseLPt: LPoint);
    VAR currParaImage:  TParaImage;
        currLP:	        INTEGER;
        textImage:      TTextImage;
        firstTxtImg:    TTextImage;
        selection:      TSelection;
        paraIndex:      LONGINT;

    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        selection := SELF.view.panel.selection;
        WHILE selection.coSelection <> NIL DO
            selection := selection.coSelection;
        IF (clickState.fShift OR (clickState.clickCount > 1)) AND InClass(selection, TTextSelection) THEN
            { let the selection extend itself }
            selection.MousePress(mouseLPt)
        ELSE
            BEGIN
            textImage := SELF.FindTextImage(mouseLPt, firstTxtImg);
            textImage.FindParaAndLp(mouseLPt, currParaImage, paraIndex, currLP);

            {If we are a coSelection then BeginSelection should already have been called when
             panel selection was created}
            IF SELF.view.panel.selection.coSelection = NIL THEN
                SELF.view.panel.BeginSelection
            ELSE
                selection.Highlight(hOnToOff);

            selection := selection.FreedAndReplacedBy(TInsertionPoint.CREATE(NIL,
                                            SELF.Heap, SELF.view, textImage, mouseLPt,
                                            currParaImage.paragraph, paraIndex, currLP));
            SELF.text.ChangeSelInOtherPanels(TTextSelection(selection));
            SELF.text.HiliteParagraphs(hOffToOn, paraIndex, currLP, paraIndex, currLP, FALSE);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    FUNCTION TTextImage.NewEditPara(initialSize: INTEGER; itsFormat: TParaFormat): TEditPara;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        NewEditPara := TEditPara.CREATE(NIL, SELF.Heap, initialSize, itsFormat);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    FUNCTION TTextImage.NewParaImage(itsParagraph: TEditPara; itsLRect: LRect;
                                    lineTop: LONGINT; lineLeft: LONGINT): TParaImage;
    VAR paraImage:  TParaImage;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        paraImage := TParaImage.CREATE(NIL, SELF.Heap, SELF.view, itsParagraph, itsLRect, lineTop, lineLeft);
        paraImage.textImage := SELF;
        itsParagraph.InsImage(paraImage);
        NewParaImage := paraImage;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    FUNCTION TTextImage.NewTextImage(heap: THeap; itsView: TView; itsLRect: LRect;
                                                itsText:TText; isGrowable: BOOLEAN): TTextImage;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        NewTextImage := TTextImage.CREATE(NIL, heap, itsView, itsLRect, itsText, isGrowable);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    FUNCTION TTextImage.NewTextSelection(firstPara: TEditPara; firstIndex: LONGINT; firstLP: INTEGER;
                                            lastPara: TEditPara; lastIndex: LONGINT; lastLP: INTEGER
                                            ): TTextSelection;
    VAR textSel:    TTextSelection;
        heap:	    THeap;
        view:	    TView;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        heap := SELF.Heap;
        view := SELF.view;
        IF firstPara = lastPara THEN
            IF firstLP = lastLP THEN
                textSel := TInsertionPoint.CREATE(NIL, heap, view, SELF, zeroLPt,
                                                        firstPara, firstIndex, firstLP)
            ELSE
                textSel := TOneParaSelection.CREATE(NIL, heap, view, SELF, zeroLPt,
                                                        firstPara, firstIndex, firstLP, lastLP)
        ELSE
            textSel := TMultiParaSelection.CREATE(NIL, heap, view, SELF, zeroLPt,
                                                        firstPara, firstIndex, firstLP,
                                                        lastPara, lastIndex, lastLP, TRUE);
        NewTextSelection := textSel;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtCld}
    PROCEDURE TTextImage.OffsetBy(deltaLPt: LPoint);
    { Can be used to quickly move a text image }
        PROCEDURE OffsetImage(obj: TObject);
        BEGIN
            TParaImage(obj).OffsetBy(deltaLPt);
        END;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        WITH deltaLPt DO
            {$H-} OffsetLRect(SELF.extentLRect, h, v); {$H+}
        SELF.imageList.Each(OffsetImage);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    PROCEDURE TTextImage.RecomputeImages(drawAction: TDrawAction; invalBits: BOOLEAN);
    LABEL   1;
    VAR drawLRect:  LRect;
        lastLP:	        INTEGER;
        lastDrawnImage: TParaImage;
        nextTxtImg:     TTextImage;
        paraImage:      TParaImage;
        s:	        TListScanner;
        tempList:       TList;
        beginAtLP:      INTEGER;
        returnLRect:    LRect;
        lastImage:      TParaImage;
        firstImage:     TParaImage;
        lastOneChanged: BOOLEAN;
        deltaLPt:       LPoint;
        currParaIndex:  LONGINT;
        paragraph:      TEditPara;
        newBottom:      LONGINT;
        realAction:     TDrawAction;
        r:	        LRect;
        {$IFC fTextTrace}
        str:	        STR255;
        {$ENDC}

        FUNCTION OnlyPartDrawn(pImage: TParaImage): BOOLEAN;
        VAR wontFit:    BOOLEAN;
            sLine:      TListScanner;
            deleteRest: BOOLEAN;
            lineInfo:   TLineInfo;

            PROCEDURE DrawPImage(obj: TObject);
            VAR action: TDrawAction;
                bits:   BOOLEAN;
            BEGIN
                {$IFC fTrace}BP(10);{$ENDC}
                bits := invalBits;
                action := realAction;
                {If the paragraph was offset, we don't want DrawPara to draw the changed lines, so
                 we display the offset paragraph case below and pass actionNone to DrawPara.
                 However, we must pass FALSE for invalBits since we still need the wasOffset flag
                 set for the display code below}
                IF pImage.wasOffset THEN
                    BEGIN
                    action := actionNone;
                    bits := FALSE;
                    END;
                pImage.DrawParaImage(drawLRect, beginAtLP, action, bits, returnLRect);
                {$IFC fTrace}EP;{$ENDC}
            END;
        BEGIN
            {$IFC fTrace}BP(10);{$ENDC}
            wontFit := FALSE;
            lastOneChanged := FALSE;
            pImage.textImage := SELF;
            {$IFC fTextTrace}
            IF fTextTrace THEN
                BEGIN
                LIntToHex(ORD(pImage), @str);
                WriteLn('++ Entering OnlyPartDrawn: pImage =', str);
                WriteLn('++			  : deltaLPt.v =', deltaLPt.v:1, '  drawLRect.top = ',
                                            drawLRect.top:1);
                END;
            {$ENDC}

            {offset pImage before recalculating so that unchanged lineInfo's get offset}
            IF drawLRect.top <> pImage.extentLRect.top THEN
                BEGIN
                deltaLPt.v := drawLRect.top - pImage.extentLRect.top;
                pImage.OffsetBy(deltaLPt);
                pImage.wasOffset := TRUE;   {so that we know what to redraw/invalidate}
                {If we moved the last paraImage up, maybe more will fit, so force call to DrawPara
                 by setting changed TRUE}
                IF (deltaLPt.v < 0) AND (pImage = SELF.imageList.Last) THEN
                    BEGIN
                    lastOneChanged := TRUE;
                    pImage.changed := TRUE;
                    END;
                END;

            IF pImage.changed THEN
                BEGIN
                lastLP := pImage.endLP;
                {$IFC fTextTrace}
                IF fTextTrace THEN
                    WriteLn('++ OnlyPartDrawn: pImage changed, about to call DrawPara; old endLP =',
                                                lastLP:1);
                {$ENDC}

                SELF.FilterAndDo(pImage, DrawPImage);

                {$IFC fTextTrace}
                IF fTextTrace THEN
                    WriteLn('++ OnlyPartDrawn: DrawPara just called; pImage.endLP =',
                                                pImage.endLP:1, ' para size = ', pImage.paragraph.size:1);
                {$ENDC}
                lastOneChanged := lastOneChanged OR (pImage.endLP <> lastLP);
                END
            ELSE IF deltaLPt.v > 0 THEN
                BEGIN
                {$IFC fTextTrace}
                IF fTextTrace THEN
                    WriteLn('++ OnlyPartDrawn: pImage.extentLRect.bottom =', pImage.extentLRect.bottom:1,
                                '  drawLRect.bottom = ', drawLRect.bottom:1);
                {$ENDC}

                wontFit := pImage.extentLRect.bottom > drawLRect.bottom;
                IF wontFit THEN
                    BEGIN
                    {Ideally, if textImages are same width, just insert extra lineInfo's
                     into first paraImage of next textImage; If they are not same width, we
                     still insert them but mark them invalid. For now just delete them}
                    lastOneChanged := TRUE;
                    sLine := pImage.lineList.Scanner;
                    deleteRest := FALSE;
                    WHILE sLine.Scan(lineInfo) DO
                        IF deleteRest THEN
                            sLine.Delete(TRUE)
                        ELSE IF lineInfo.lineLRect.bottom > drawLRect.bottom THEN
                            BEGIN
                            {If the first lineInfo won't fit then set pImage.endLP to -1, indicating that
                             none of the paragraph fit}
                            IF sLine.Position = 1 THEN
                                BEGIN
                                sLine.Done;
                                pImage.endLP := -1;
                                END
                            ELSE
                                BEGIN
                                pImage.extentLRect.bottom := lineInfo.lineLRect.top;
                                pImage.endLP := lineInfo.startLP;
                                sLine.Delete(TRUE);
                                deleteRest := TRUE;
                                END;
                            END;
                    END;
                END;

            drawLRect.top := pImage.extentLRect.bottom;
            lastLP := pImage.endLP;
            wontFit := wontFit OR (pImage.endLP <> pImage.paragraph.size);
            IF pImage.wasOffset AND (lastLP >= 0) THEN
                BEGIN
                r := pImage.extentLRect;
                InsetLRect(r, -1, 0);
                IF realAction = actionDraw THEN
                    BEGIN
                    FillLRect(r, lPatWhite);
                    pImage.RedrawLines(0, MAXINT);
                    END
                ELSE IF realAction = actionInval THEN
                    thePad.InvalLRect(r);
                pImage.wasOffset := NOT invalBits;
                pImage.changed := FALSE;
                END;

            {after the first paragraph is drawn, reset beginAtLP}
            beginAtLP := 0;
            IF NOT wontFit THEN
                currParaIndex := currParaIndex + 1;
            {$IFC fTextTrace}
            IF fTextTrace THEN
                WriteLn('++ EXITING OnlyPartDrawn: deltaLPt.v =', deltaLPt.v:1, '  wontFit = ', wontFit);
            {$ENDC}


            {return TRUE when a paragraph does not get completely displayed}
            OnlyPartDrawn := wontFit;
            {$IFC fTrace}EP;{$ENDC}
        END;

    BEGIN {RecomputeIMages}
        {$IFC fTrace}BP(10);{$ENDC}
        IF SELF = SELF.headTxtImg THEN
            SELF.SetFirstIndex;
        currParaIndex := SELF.firstIndex;
        drawLRect := SELF.extentLRect;
        IF SELF.growsDynamically THEN
            drawLRect.bottom := SELF.view.extentLRect.bottom;
        realAction := drawAction;
        IF drawAction = actionDraw THEN
            IF NOT SELF.view.OKToDrawIn(drawLRect) OR deferUpdate THEN
                realAction := actionInval;

        beginAtLP := SELF.startLP;
        deltaLPt := zeroLPt;

        {Recompute paragraphs until we reach the end of our imageList or no more will fit}
        {Use GOTO so we can hold on to the scanner if needed}
        s := SELF.imageList.Scanner;
        WHILE s.Scan(lastDrawnImage) DO
            IF OnlyPartDrawn(lastDrawnImage) THEN
                GOTO 1;

        1:
        {$IFC fTextTrace}
        IF fTextTrace THEN
            BEGIN
            LIntToHex(ORD(lastDrawnImage), @str);
            WriteLn('++ RecomputeImages: Just fell out of OnlyPartDrawn loop: lastDrawnImage=',
                            str, '  lastOneChanged=', lastOneChanged);
            END;
        {$ENDC}

        {At this point, lastDrawnImage will be NIL iff the scan went through the entire list
         and OnlyPartDrawn never returned TRUE}

        {Hence, if lastDrawnImage is NIL, then we displayed all our paraImages and there may
         still be some space left, so steal the next textImage's paraImages (if any).  Continue
         this in the Repeat loop until we use up the space or exhaust the paraImages.  Note that we
         don't need to check nextTxtImg if none of the paraImages changed and had to be recalculated}
        nextTxtImg := SELF.nextTxtImg;
        IF lastDrawnImage = NIL THEN
            BEGIN
            IF lastOneChanged OR TRUE THEN  {<-- temporary!!??}
                REPEAT
                    IF nextTxtImg <> NIL THEN
                        BEGIN
                        s := nextTxtImg.imageList.Scanner;

                        {Delete the first paraImage in the next textImage if it pointed to the same
                         paragraph as the current textImage's last paraImage, since, if we got to
                         this point, we must have already displayed the whole paragraph}
                        IF (nextTxtImg.imageList.Size > 0) AND (SELF.imageList.Size > 0) THEN
                            BEGIN
                            firstImage := TParaImage(nextTxtImg.imageList.First);
                            lastImage := TParaImage(SELF.imageList.Last);
                            IF firstImage.paragraph = lastImage.paragraph THEN
                                IF s.Scan(paraImage) THEN
                                    BEGIN
                                    paraImage.paragraph.images.DelObject(paraImage, FALSE);
                                    s.Delete(TRUE);
                                    END;
                            END;
                        WHILE s.Scan(lastDrawnImage) DO
                            BEGIN
                            lastDrawnImage.InvalLinesWith(0, MAXINT);
                            deltaLPt.v := 0;
                            IF OnlyPartDrawn(lastDrawnImage) THEN
                                BEGIN
                                {if we didn't stop between paragraphs, install the paraImage in our list,
                                 replace the next textImage's first paraImage with a copy of this one,
                                 then terminate the scan.  Note that the extentLRect and
                                 height fields of the next TextImage's first paraImage are now incorrect,
                                 but will be rectified when nextTxtImg.RecomputeImage is called}
                                IF (lastLP >= 0) THEN
                                    BEGIN
                                    SELF.imageList.InsLast(lastDrawnImage);
                                    paraImage := nextTxtImg.NewParaImage(lastDrawnImage.paragraph,
                                                        lastDrawnImage.extentLRect, 0, 0);
                                    s.Replace(paraImage, FALSE);
                                    END;
                                s.Done;
                                END
                            ELSE
                                BEGIN
                                {remove lastDrawnImage from nextTxtImg.imageList and install in
                                 SELF.imageList}
                                s.Delete(FALSE);
                                SELF.imageList.InsLast(lastDrawnImage);
                                END;
                            END;
                        IF lastDrawnImage = NIL THEN
                            nextTxtImg := nextTxtImg.nextTxtImg;
                        END;
                UNTIL (lastDrawnImage <> NIL) OR (nextTxtImg = NIL);

            IF lastDrawnImage = NIL THEN
                BEGIN
                {We exhausted all of the images and there is still potentially some room, so
                 look at the paragraph list and see if there are some paragraphs for which no
                 paraImages have yet been generated.
                 NOTE: this is where initial imaging of text without paraImages will be routed}
                IF currParaIndex <= SELF.text.paragraphs.Size THEN
                    BEGIN
                    s := SELF.text.paragraphs.ScannerFrom(currParaIndex-1, scanForward);
                    WHILE s.Scan(paragraph) DO
                        BEGIN
                        lastDrawnImage := SELF.NewParaImage(paragraph, drawLRect, 0, 0);
                        IF OnlyPartDrawn(lastDrawnImage) THEN
                            s.Done;
                        IF lastdrawnImage.endLP >= 0 THEN
                            SELF.imageList.InsLast(lastDrawnImage)
                        ELSE
                            BEGIN
                            lastDrawnImage.paragraph.images.DelObject(lastDrawnImage, TRUE);
                            lastDrawnImage := NIL;
                            END;
                        END;
                    END;
                END;
            END
        ELSE IF nextTxtImg <> NIL THEN
            BEGIN
            IF lastOneChanged THEN
                BEGIN
                {we stopped displaying in the middle of a paragraph, so give the rest of our
                 paraImages to the next textImage (note that the scanner (s) is still valid
                 because we jumped out of scan loop above)}
                {put rest of SELF.imageList paraImages in tempList, then insert tempList into nextTxtImg}
                tempList := TList.CREATE(NIL, SELF.Heap, 0);
                {if we didn't display any of the current paraImage then delete it from this list}
                IF lastLP < 0 THEN
                    BEGIN
                    {$IFC fTextTrace}
                    IF fTextTrace THEN
                        BEGIN
                        LIntToHex(ORD(lastDrawnImage), @str);
                        WriteLn('++ RecomputeImages: lastLP < 0; lastdrawnImage=', str);
                        END;
                    {$ENDC}
                    s.Delete(FALSE);
                    paraImage := lastDrawnImage;
                    paraImage.endLP := 0;
                    END
                ELSE
                    BEGIN
                    paraImage := nextTxtImg.NewParaImage(lastDrawnImage.paragraph,
                                                    lastDrawnImage.extentLRect, 0, 0);
                    {$IFC fTextTrace}
                    IF fTextTrace THEN
                        BEGIN
                        LIntToHex(ORD(paraImage), @str);
                        WriteLn('++ RecomputeImages: copy of lastDrawnImage =', str);
                        END;
                    {$ENDC}
                    END;
                tempList.InsLast(paraImage);
                {put the paraImages into tempList in reverse order so that we can scan it and insert
                 the images at the beginning of nextTxtImg.imageList (a double-reverse)}
                WHILE s.Scan(paraImage) DO
                    BEGIN
                    {$IFC fTextTrace}
                    IF fTextTrace THEN
                       BEGIN
                       LIntToHex(ORD(paraImage), @str);
                       WriteLn('++ RecomputeImages: appending to tempList and deleting from SELF pImg=', str);
                       END;
                    {$ENDC}
                    tempList.InsFirst(paraImage);
                    s.Delete(FALSE);
                    END;

                {Delete the last paraImage inserted in the tempList if it pointed to the same
                 paragraph as the next textImage's first paraImage}
                IF nextTxtImg.imageList.Size > 0 THEN
                    BEGIN
                    firstImage := TParaImage(nextTxtImg.imageList.First);
                    lastImage := TParaImage(tempList.First);
                    IF firstImage.paragraph = lastImage.paragraph THEN
                        BEGIN
                        firstImage.InvalLinesWith(0, MAXINT);
                       {$IFC fTextTrace}
                        IF fTextTrace THEN
                            BEGIN
                            LIntToHex(ORD(lastImage), @str);
                            WriteLn('++ RecomputeImages: ', str,
                                ' points to same para as nxtTxt.firstImg, so tempList.del');
                            END;
                        {$ENDC}
                        IF lastDrawnImage = lastImage THEN
                            lastDrawnImage := NIL;
                        lastImage.paragraph.images.DelObject(lastImage, FALSE);
                        tempList.DelFirst(TRUE);
                        END;
                    END;
                {$IFC fTextTrace}
                IF fTextTrace THEN
                    WriteLn('++ RecomputeImages: About to insert rest of pimages into nextTImage; list size=',
                                    tempList.Size:1);
                {$ENDC}
                s := tempList.Scanner;
                WHILE s.Scan(paraImage) DO
                    BEGIN
                    paraImage.textImage := nextTxtImg;
                    paraImage.InvalLinesWith(0, MAXINT);
                    nextTxtImg.imageList.InsFirst(paraImage);
                    s.Delete(FALSE);
                    END;
                tempList.Free;
                END; {lastOneChanged}
            END {nxtTxtImg <> NIL}
        ELSE
            {If we have stopped displaying in the middle of a paragraph and there is no next
             text image to display the excess, then delete the remaining paraImages}
            BEGIN
            IF lastLP < 0 THEN
                BEGIN
                lastDrawnImage.paragraph.images.DelObject(lastDrawnImage, FALSE);
                s.Delete(TRUE);
                END;
            WHILE s.Scan(paraImage) DO
                BEGIN
                paraImage.paragraph.images.DelObject(paraImage, FALSE);
                s.Delete(TRUE);
                END;
            END;

        {Set up new bottom and erase any garbage due to text moving up}
        newBottom := SELF.ImageBottom;
        IF newBottom < SELF.formerBottom THEN
            WITH SELF, extentLRect DO
                {$H-}
                BEGIN
                SetLRect(updateLRect, left-1, newBottom, right+1, formerBottom);
                IF realAction = actionDraw THEN
                    FillLRect(updateLRect, lPatWhite)
                ELSE IF realAction = actionInval THEN
                    thePad.invalLRect(updateLRect);
                IF invalBits THEN
                    updateLRect := zeroLRect;
                END;
                {$H+}
        SELF.formerBottom := newBottom;
        IF SELF.growsDynamically THEN
            WITH SELF, extentLRect DO
                {$H-}
                bottom := Max(newBottom, top + minHeight);
                {$H+}


        {Now tell the next textImage in the chain to recompute itself}
        nextTxtImg := SELF.nextTxtImg;
        IF nextTxtImg <> NIL THEN
            BEGIN
            {$IFC fTextTrace}
            IF fTextTrace THEN
                WriteLn('++ RecomputeImages: About to call RecomputeImages for nextTxtImg; nTI.imgLst.Size=',
                                nextTxtImg.imageList.Size:1);
            {$ENDC}
            IF lastDrawnImage = NIL THEN
                nextTxtImg.startLP := 0
            ELSE
                {$H-} nextTxtImg.startLP := Max(0, lastDrawnImage.endLP); {$H+}
            nextTxtImg.firstIndex := currParaIndex;
            nextTxtImg.RecomputeImages(drawAction, invalBits);
            END;

        {$IFC fTrace}EP;{$ENDC}
    END; {RecomputeImages}


{$S SgTxtCld}
    PROCEDURE TTextImage.Resize(newExtent: LRect);
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.extentLRect := newExtent;
        SELF.InvalAll;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtHot}
    FUNCTION TTextImage.SeesSameAs(image: TImage): BOOLEAN;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        IF SELF = image THEN
            SeesSameAs := TRUE
        ELSE IF InClass(image, TParaImage) THEN
            SeesSameAs := SELF.text = TParaImage(image).textImage.text
        ELSE IF InClass(image, TTextImage) THEN
            SeesSameAs := SELF.text = TTextImage(image).text
        ELSE
            SeesSameAs := FALSE;
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtHot}
    PROCEDURE TTextImage.SetFirstIndex;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.firstIndex := 1;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtWrm}
    FUNCTION  TTextImage.TxtImgForClipBoard(heap: THeap; itsView: TView; itsLRect: LRect;
                                                itsText:TText; isGrowable: BOOLEAN): TTextImage;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        TxtImgForClipBoard := TTextImage.CREATE(NIL, heap, itsView, itsLRect, itsText, isGrowable);
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtIni}
END; {Methods of TTextImage}


METHODS OF TTextView;

{$S SgTxtCld}
    FUNCTION TTextView.CREATE(object: TObject; heap: THeap; itsPanel: TPanel; itsExtent: LRect): TTextView;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TTextView(itsPanel.NewView(object, itsExtent, TPrintManager.CREATE(NIL, heap),
                                                stdMargins, FALSE {, Damnit!}));
        SELF.textImage := NIL;
        SELF.valid := FALSE;
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtCld}
{$IFC fTextTrace}
    PROCEDURE TTextView.Fields(PROCEDURE Field(nameAndType: S255));
    BEGIN
        SUPERSELF.Fields(Field);
        Field('textImage: TTextImage');
        Field('valid: BOOLEAN');
        Field('');
    END;
{$ENDC}

{$S SgTxtCld}
{$IFC fUseUnivText}
    PROCEDURE TTextView.CreateUniversalText;
    VAR univText:   TTextWriteUnivText;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        IF NOT clipBoard.hasUniversalText THEN
            BEGIN
            univText := TTextWriteUnivText.CREATE(NIL, mainHeap, NIL, 512,
                                                        TTextSelection(SELF.panel.selection));
            univText.Free;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
{$ENDC}


{$S SgTxtCld}
    FUNCTION TTextView.CursorAt(mouseLPt: LPoint): TCursorNumber;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        IF LPtInLRect(mouseLPt, SELF.textImage.extentLRect) THEN
            CursorAt := textCursor
        ELSE
            CursorAt := arrowCursor;
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtCld}
    PROCEDURE TTextView.Draw;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        IF NOT SELF.valid THEN
            BEGIN
            SELF.textImage.RecomputeImages(actionNone, TRUE);
            SELF.valid := TRUE;
            END;
        SELF.textImage.Draw;
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtCld}
    PROCEDURE TTextView.MousePress(mouseLPt: LPoint);
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SELF.textImage.MousePress(mouseLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgTxtIni}
END; {Methods of TTextView}

{$S SgTxtCld}

{$IFC fUseUnivText}
METHODS OF TTextWriteUnivText;

{$S SgTxtCld}
    FUNCTION  TTextWriteUnivText.CREATE(object: TObject; heap: THeap;
                                                itsString: TString; itsDataSize: INTEGER;
                                                itsTextSel: TTextSelection): TTextWriteUnivText;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        WITH TTextWriteUnivText(object) DO
            BEGIN
            textSelection := itsTextSel;
            currIndex := 1;
            currPara := itsTextSel.textRange.firstPara;
            currLP := 0;
            currStyleIndex := 1;
            currTStyles := itsTextSel.textRange.firstPara.typeStyles;
            END;

        SELF := TTKWriteUnivText.CREATE(object, heap, itsString, itsDataSize);
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtCld}
{$IFC fTextTrace}
    PROCEDURE TTextWriteUnivText.Fields(PROCEDURE Field(nameAndType: S255));
    BEGIN
        SUPERSELF.Fields(Field);
        Field('textSelection: TTextSelection');
        Field('currIndex: LONGINT');
        Field('currPara: TEditPara');
        Field('currLP: INTEGER');
        Field('currStyleIndex: INTEGER');
        Field('currTStyles: TArray');
        Field('');
    END;
{$ENDC}

{$S SgTxtCld}
    PROCEDURE TTextWriteUnivText.FillParagraph;
    VAR startPos:   INTEGER;
        endPos:	    INTEGER;
        currChange: TStyleChange;
        nextChange: TStyleChange;
        numChars:   INTEGER;
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        {$IFC fTextTrace}
        IF fTextTrace THEN
            BEGIN
            WriteLn('<-> Entering FillRun: Current fields are:');
            WriteLn('<->        currIndex = ', SELF.currIndex:1, ' currStyleIndex = ', SELF.currStyleIndex:1);
            WriteLn('<->        currLP = ', SELF.currLP:1);
            END;
        {$ENDC}
        SELF.data.DelAll;
        IF SELF.currIndex <= SELF.textSelection.textRange.lastIndex THEN
            BEGIN
            WITH SELF.paragraphDescriptor, SELF.currPara.format DO
                BEGIN
                paragraphStart := SELF.textSelection.isParaSelection AND {LSR}
                                        (SELF.currLP = 0);
                firstLineMargin := firstIndent;
                bodyMargin := leftIndent;
                rightMargin := rightMargin - rightIndent; {????}
                paraLeading := spaceBelowPara;
                END;
            IF SELF.currPara.size = 0 THEN
                BEGIN
                endPos := 0;
                numChars := 0;
                END
            ELSE
                BEGIN
                REPEAT
                    SELF.currTStyles.GetAt(SELF.currStyleIndex, @currChange);
                    WITH SELF.characterDescriptor DO
                        BEGIN
                        {$H-}
                        font := QDFontNumber(currChange.newStyle);
                        {$H+}
                        face := currChange.newStyle.onFaces;
                        END;
                    startPos := Max(SELF.currLP, currChange.lp) + 1;
                    SELF.currTStyles.GetAt(SELF.currStyleIndex+1, @nextChange);
                    endPos := Min(SELF.currPara.size, nextChange.lp);
                    numChars := endPos - startPos + 1;
                    IF numChars = 0 THEN
                        SELF.currStyleIndex := SELF.currStyleIndex + 1;
                UNTIL numChars > 0;
                SELF.data.InsManyAt(1, SELF.currPara, startPos, numChars);
                END;
            IF endPos = SELF.currPara.size THEN
                BEGIN
                SELF.currIndex := SELF.currIndex + 1;
                WITH SELF DO
                    IF currIndex <= textSelection.textRange.lastIndex THEN
                        BEGIN
                        currLP := 0;
                        currStyleIndex := 1;
                        {$H-}
                        currPara := TEditPara(SELF.textSelection.textImage.text.paragraphs.At(
                                                            SELF.currIndex));
                        {$H+}
                        currTStyles := currPara.typeStyles;
                        {$H-}
                        SELF.data.InsAt(numChars+1, CHR(ascReturn)); {last statement in IF!!}
                        {$H+}
                        END
                    ELSE IF textSelection.isParaSelection THEN
                        {$H-}
                        SELF.data.InsAt(numChars+1, CHR(ascReturn)); {last statement in IF!!}
                        {$H+}
                END
            ELSE
                BEGIN
                SELF.currLP := SELF.currLP + numChars;
                SELF.paragraphDescriptor.additionalChrInParagraph :=  {LSR}
                        SELF.currPara.size - endPos + 1;
                END;
            END;
        {$IFC fTextTrace}
        IF fTextTrace THEN
            BEGIN
            WriteLn;
            WriteLn('>-< EXITING FillRun: Current fields are:');
            WriteLn('>-<        currIndex = ', SELF.currIndex:1, ' currStyleIndex = ', SELF.currStyleIndex:1);
            WriteLn('>-<        currLP = ', SELF.currLP:1);
            WriteLn('----------------------------------------------------------------');
            END;
        {$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S SgTxtIni}
END; {Methods of TTextWriteUnivText}
{$ENDC}

{$S SgTxtIni}



